#include "pid.h"

PID::PID(float point, float kp, float ki, float kd) {
    _kp            = kp;
    _ki            = ki;
    _kd            = kd;
    _point         = point;
    output_max     = 10000;
    output_min     = -10000;
    integral_max   = 10000;
    integral_min   = -10000;
    error_integral = 0;
    _dir           = 1;
}

float PID::Update(float input) {
    float output;
    float dinput;
    error = _point - input;
    error_integral += _ki * error + error_integral_offset;
    if (error_integral > integral_max) {
        error_integral = integral_max;
    }
    if (error_integral < integral_min) {
        error_integral = integral_min;
    }
    dinput     = input - input_last;
    output     = _kp * error + error_integral - _kd * dinput;
    input_last = input;
    if (output < output_min) {
        output = output_min;
    }
    if (output > output_max) {
        output = output_max;
    }
    return output;
}

void PID::SetOutputLimits(float max_out, float min_out) {
    output_max = max_out;
    output_min = min_out;
}

void PID::SetIntegralLimits(float max_out, float min_out) {
    integral_max = max_out;
    integral_min = min_out;
}

void PID::SetDirection(int8_t dir) {
    _dir = dir;
    _kp  = fabs(_kp) * _dir;
    _ki  = fabs(_ki) * _dir;
    _kd  = fabs(_kd) * _dir;
}

void PID::SetIntegral(float integral) {
    error_integral = integral;
}

void PID::SetIntegralOffset(float offset) {
    error_integral_offset = offset;
}

void PID::UpdateParam(float kp, float ki, float kd) {
    _kp = fabs(kp) * _dir;
    _ki = fabs(ki) * _dir;
    _kd = fabs(kd) * _dir;
}

void PID::SetPoint(float point) {
    _point = point;
}
